package cn.mw.cmdb.service.impl;

import cn.mw.cmdb.entity.InstanceInfo;
import cn.mw.cmdb.entity.UManageInitDataCabinetPortInfo;
import cn.mw.cmdb.entity.V6800InitDataInfo;
import cn.mw.cmdb.enums.UNumManageLightState;
import cn.mw.cmdb.exception.WarnParamTitleException;
import cn.mw.cmdb.mongoMapper.UNumManageMapper;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.components.mongodb.entity.MongoPropertyType;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.microMonitorCommon.util.SpringUtils;
import com.alibaba.nacos.shaded.com.google.common.base.Strings;
import com.mongodb.client.model.UpdateOneModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.bson.Document;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;

import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.config.MQTT.MessageArrivedByV6800.sendUManageLightState;
import static cn.mw.cmdb.config.MQTT.MessageArrivedHandle.UMonitorModelIdKey;
import static cn.mw.cmdb.config.MQTT.MessageArrivedHandle.onlineStatePath;
import static cn.mw.cmdb.config.MQTT.OnlineStateEnum.offline;
import static cn.mw.cmdb.config.MQTT.OnlineStateEnum.online;
import static cn.mw.cmdb.entity.InstanceInfo.SearchPrefix;
import static cn.mw.cmdb.entity.PropertyType.relationIdKey;
import static cn.mw.cmdb.enums.UNumManageLightState.PrecedUnused;
import static cn.mw.cmdb.enums.UNumManageLightState.PrecedUsed;
import static cn.mw.cmdb.service.impl.InstanceServiceImpl.relationRoomIdPath;
import static cn.mw.cmdb.util.ValConvertUtil.intValueConvert;
import static cn.mw.cmdb.util.ValConvertUtil.strValueConvert;
import static cn.mw.cmdb.viewProcessor.ModelViewCabinetProcess.*;
import static cn.mw.cmdb.viewProcessor.ModelViewUNumProcess.*;

/**
 * U位管理
 */
@Slf4j
public class UNumManageServiceImpl extends ModelBaseServiceImpl<V6800InitDataInfo, Object> {
    public static final String ID = "uNumManage";
    public static final String moduleSnMatchKey = "data.$.moduleSn";
    public static final String moduleUNumMatchKey = "data.$.moduleUNum";
    public static final String moduleMNumMatchKey = "data.$.moduleMNum";

    public static final String cabinetCodePath = SearchPrefix + "." + cabinetCode;

    private UNumManageMapper uNumManageMapper;
    private CmdbServiceManage cmdbServiceManage;


    public UNumManageServiceImpl(UNumManageMapper uNumManageMapper, CmdbServiceManage cmdbServiceManage) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.uNumManageMapper = uNumManageMapper;
    }

    @Override
    public V6800InitDataInfo genObject() {
        return null;
    }

    @Override
    Object doAdd(V6800InitDataInfo param) throws Exception {
        return null;
    }

    @Override
    boolean doUpdate(V6800InitDataInfo param) throws Exception {
        Query query = new Query(CriteriaWrapper.where(V6800InitDataInfo::getGatewayIp).is(param.getGatewayIp()));
        Update update = CMDBTool.genMongoUpdate(param, null, null);
        uNumManageMapper.upsert(query, update);
        return true;
    }

    @Override
    boolean doRemove(V6800InitDataInfo param) throws Exception {
        return false;
    }

    @Override
    Object doBatchAdd(Object params) throws Exception {
        return null;
    }

    @Override
    boolean doBatchUpdate(Object params) throws Exception {
        return false;
    }

    @Override
    V6800InitDataInfo doSelectById(Object id) throws Exception {
        return null;
    }

    @Override
    List<V6800InitDataInfo> doSelectList(Object param) throws Exception {
        return null;
    }

    @Override
    boolean doBatchRemove(Object params) throws Exception {
        return false;
    }

    /**
     * 初始化数据
     *
     * @param v6800InitDataInfo
     * @throws Exception
     */
    public void syncDeviceInitData(V6800InitDataInfo v6800InitDataInfo) throws Exception {
        List<UpdateOneModel<Document>> updates = new ArrayList<>();
        String gatewayIp = v6800InitDataInfo.getGatewayIp();
        String gatewaySn = v6800InitDataInfo.getGatewaySn();
        List<Pair<Query, Update>> updateList = new ArrayList<>();
        //UNORDERED是异步执行，有错误跳过继续执行；ORDERED时有序执行，遇到错误终止
        BulkOperations operations = uNumManageMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, V6800InitDataInfo.class);
        for (UManageInitDataCabinetPortInfo dataItem : v6800InitDataInfo.getData()) {
            Integer moduleIndex = dataItem.getModuleIndex();
            String moduleSn = dataItem.getModuleSn();
            Integer moduleUNum = dataItem.getModuleUNum();
            Integer moduleMNum = dataItem.getModuleMNum();
            // 添加查询条件
            Query query = new Query(CriteriaWrapper.where(V6800InitDataInfo::getGatewayIp).is(gatewayIp));
            query.addCriteria(CriteriaWrapper.where(V6800InitDataInfo::getData).elemMatch(CriteriaWrapper.where(UManageInitDataCabinetPortInfo::getModuleIndex).is(strValueConvert(moduleIndex))));
            Update update = new Update();
            // 更新数据
            update.set(CMDBTool.getFieldName(V6800InitDataInfo::getGatewaySn), gatewaySn).set(moduleSnMatchKey, moduleSn).set(moduleUNumMatchKey, moduleUNum).set(moduleMNumMatchKey, moduleMNum);
            Pair<Query, Update> updatePair = Pair.of(query, update);
            updateList.add(updatePair);
        }
        operations.updateMulti(updateList);
        operations.execute();
    }

    /**
     * 根据机柜id或机柜code，获取U位管理的查询参数
     *
     * @param param
     * @return
     * @throws Exception
     */
    public MwCabinetRelationUNumParam getUNumCabinetRelationInfo(MwCabinetRelationUNumParam param) throws Exception {
        MwCabinetRelationUNumParam relationUNumParam = new MwCabinetRelationUNumParam();
        String cabinetCodeStr = "";
        if (!Strings.isNullOrEmpty(param.getCabinetCode())) {
            cabinetCodeStr = param.getCabinetCode();
        } else {
            if (!Strings.isNullOrEmpty(param.getInstanceId())) {
                InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
                InstanceInfo instanceInfo = instanceService.getInstanceInfoById(param.getInstanceId());
                if (instanceInfo.getData() != null) {
                    cabinetCodeStr = strValueConvert(instanceInfo.getData().get(cabinetCode));
                }
            }
        }
        Query query = new Query(CriteriaWrapper.where(V6800InitDataInfo::getData).elemMatch(CriteriaWrapper.where(UManageInitDataCabinetPortInfo::getCabinetCode).is(cabinetCodeStr)));
        V6800InitDataInfo initDataInfo = uNumManageMapper.findOne(query);
        if (initDataInfo != null && !Strings.isNullOrEmpty(initDataInfo.getGatewaySn()) && CollectionUtils.isNotEmpty(initDataInfo.getData())) {
            String finalCabinetCodeStr = cabinetCodeStr;
            List<UManageInitDataCabinetPortInfo> collect = initDataInfo.getData().stream().filter(s -> !Strings.isNullOrEmpty(s.getCabinetCode()) && s.getCabinetCode().equals(finalCabinetCodeStr)).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(collect)) {
                UManageInitDataCabinetPortInfo cabinetPortInfo = collect.get(0);
                relationUNumParam.setModuleSn(cabinetPortInfo.getModuleSn());
                relationUNumParam.setModuleIndex(cabinetPortInfo.getModuleIndex());
            }

        } else {
            throw new WarnParamTitleException("cabinet_info_no_init", cabinetCodeStr);
        }
        relationUNumParam.setInstanceId(param.getCabinetCode());
        relationUNumParam.setGatewaySn(initDataInfo.getGatewaySn());
        return relationUNumParam;
    }

    /**
     * 根据机柜id或机柜code，获取U位管理的查询参数
     *
     * @param param
     * @return
     * @throws Exception
     */
    public List<MwCabinetRelationUNumParam> getUNumCabinetRelationInfos(QueryUNumCabinetRelationParam param) throws Exception {
        List<MwCabinetRelationUNumParam> paramList = new ArrayList<>();
        List<String> cabinetCodeList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(param.getInstanceIds())) {
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            List<InstanceInfo> instanceInfos = instanceService.doListByIdsNotAuth(param.getInstanceIds());
            if (CollectionUtils.isNotEmpty(instanceInfos)) {
                for (InstanceInfo instanceInfo : instanceInfos) {
                    MwCabinetRelationUNumParam relationUNumParam = new MwCabinetRelationUNumParam();
                    if (instanceInfo.getData() != null) {
                        String cabinetCodeStr = strValueConvert(instanceInfo.getData().get(cabinetCode));
                        cabinetCodeList.add(cabinetCodeStr);
                        relationUNumParam.setCabinetCode(cabinetCodeStr);
                    }
                    relationUNumParam.setInstanceId(instanceInfo.getId());
                    paramList.add(relationUNumParam);
                }
            }
        }
        Map<String, MwCabinetRelationUNumParam> collectMap = paramList.stream().filter(s -> !Strings.isNullOrEmpty(s.getCabinetCode())).collect(Collectors.toMap(s -> s.getCabinetCode(), s -> s, (
                value1, value2) -> {
            return value2;
        }));


        if (CollectionUtils.isNotEmpty(cabinetCodeList)) {
            Query query = new Query(CriteriaWrapper.where(V6800InitDataInfo::getData).elemMatch(CriteriaWrapper.where(UManageInitDataCabinetPortInfo::getCabinetCode).in(cabinetCodeList)));
            List<V6800InitDataInfo> initDatas = uNumManageMapper.find(query);
            if (CollectionUtils.isNotEmpty(initDatas)) {
                for (V6800InitDataInfo initDataInfo : initDatas) {
                    if (initDataInfo != null && !Strings.isNullOrEmpty(initDataInfo.getGatewaySn()) && CollectionUtils.isNotEmpty(initDataInfo.getData())) {
                        List<UManageInitDataCabinetPortInfo> data = initDataInfo.getData();
                        for (UManageInitDataCabinetPortInfo initDataCabinet : data) {
                            String cabinetCodeStr = initDataCabinet.getCabinetCode();
                            if (collectMap != null && collectMap.containsKey(cabinetCodeStr)) {
                                MwCabinetRelationUNumParam relationUNumParam1 = collectMap.get(cabinetCodeStr);
                                relationUNumParam1.setGatewaySn(initDataInfo.getGatewaySn());
                                relationUNumParam1.setModuleIndex(initDataCabinet.getModuleIndex());
                                relationUNumParam1.setModuleSn(initDataCabinet.getModuleSn());
                            }
                        }
                    } else {
                        throw new WarnParamTitleException("cabinet_info_no_init", initDataInfo.getId());
                    }
                }
            }
        }
        return paramList;
    }

    /**
     * 上架设备设置预占用位置
     *
     * @param putOnDeviceList 上架设备
     */
    public void putOnDeviceSettingLightState(List<InstanceInfo> putOnDeviceList) throws Exception {
        settingLightState(putOnDeviceList, PrecedUsed);
    }

    /**
     * 下架设备设置预释放位置
     *
     * @param putOnDeviceList 下架设备
     */
    public void putDownDeviceSettingLightState(List<InstanceInfo> putOnDeviceList) throws Exception {
        settingLightState(putOnDeviceList, PrecedUnused);
    }


    private void settingLightState(List<InstanceInfo> putOnDeviceList, UNumManageLightState lightState) throws Exception {
        Set<String> relationCabinetIds = new HashSet<>();
        //资产实例数据，服务器，交换机等
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(putOnDeviceList)) {
            //所属机柜id分组下的实例数据
            Map<String, List<InstanceInfo>> relationCabinetIdMap = putOnDeviceList.stream().filter(s -> s.getData() != null && !Strings.isNullOrEmpty(strValueConvert(((Map) s.getData().get(relationCabinet)).get(relationIdKey)))).collect(Collectors.groupingBy(s -> strValueConvert(((Map) s.getData().get(relationCabinet)).get(relationIdKey))));
            relationCabinetIds = putOnDeviceList.stream().filter(s -> s.getData() != null && !Strings.isNullOrEmpty(strValueConvert(((Map) s.getData().get(relationCabinet)).get(relationIdKey)))).map(s -> MongoPropertyType.strValueConvert(((Map) s.getData().get(relationCabinet)).get(relationIdKey))).collect(Collectors.toSet());
            CmdbServiceManage cmdbServiceManage = SpringUtils.getBean(CmdbServiceManage.class);
            InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
            //根据机柜id获取对应的机柜数据
            List<InstanceInfo> cabinetInfos = instanceService.doListByIdsNotAuth(new ArrayList<>(relationCabinetIds));
            //取机柜的占用规则
            Map<String, String> cabinetRuleMapById = cabinetInfos.stream().filter(s -> s.getData() != null).collect(Collectors.toMap(s -> s.getId(), s -> strValueConvert(s.getData().get(cabinetRuleType))));

            UNumManageServiceImpl uNumManageService = (UNumManageServiceImpl) cmdbServiceManage.getModelService(UNumManageServiceImpl.ID);
            QueryUNumCabinetRelationParam param = new QueryUNumCabinetRelationParam();
            param.setInstanceIds(new ArrayList<>(relationCabinetIds));
            List<MwCabinetRelationUNumParam> uNumCabinetRelationInfos = uNumManageService.getUNumCabinetRelationInfos(param);
            //根据gatewaySn分组
            Map<String, List<MwCabinetRelationUNumParam>> MwCabinetRelationUNumMap = uNumCabinetRelationInfos.stream().filter(s -> !Strings.isNullOrEmpty(s.getGatewaySn())).collect(Collectors.groupingBy(s -> s.getGatewaySn()));

            //需要根据gatewaySn来设置U位的灯的信息，所有的信息按照gatewaySn来分类
            for (Map.Entry<String, List<MwCabinetRelationUNumParam>> entry : MwCabinetRelationUNumMap.entrySet()) {
                //每个gatewaySn作为一次请求
                String gatewaySn = entry.getKey();
                List<MwCabinetRelationUNumParam> listInfos = entry.getValue();
                V6800SetUIndexColorParam colorParam = new V6800SetUIndexColorParam();
                colorParam.setGateway_sn(gatewaySn);
                List<V6800SetUIndexColorJsonParam> indexColorList = new ArrayList<>();

                //U位数据整理
                for (MwCabinetRelationUNumParam relationUNumParam : listInfos) {
                    V6800SetUIndexColorJsonParam colorJsonParam = new V6800SetUIndexColorJsonParam();
                    colorJsonParam.setExtend_module_sn(relationUNumParam.getModuleSn());
                    colorJsonParam.setHost_gateway_port_index(relationUNumParam.getModuleIndex());
                    //获取对应的机柜id
                    String instanceId = relationUNumParam.getInstanceId();
                    if (relationCabinetIdMap != null && relationCabinetIdMap.containsKey(instanceId)) {
                        List<InstanceInfo> instanceInfoList = relationCabinetIdMap.get(instanceId);
                        List<V6800SetUIndexColorDataListParam> u_color_data = new ArrayList<>();
                        for (InstanceInfo instanceInfo : instanceInfoList) {
                            String ruleType = cabinetRuleTypeUpKey;
                            if (instanceInfo.getData() != null) {
                                String relationCabinetId = strValueConvert(strValueConvert(((Map) instanceInfo.getData().get(relationCabinet)).get(relationIdKey)));
                                if (cabinetRuleMapById != null && cabinetRuleMapById.containsKey(relationCabinetId)) {
                                    ruleType = cabinetRuleMapById.get(relationCabinetId);
                                }
                                if (instanceInfo.getData() != null) {
                                    Map<String, Object> data = instanceInfo.getData();
                                    //设备高度
                                    int UHeight = intValueConvert(data.get(deviceHeight)) == 0 ? 1 : intValueConvert(data.get(deviceHeight));
                                    if (data.get(deviceUIndex) != null) {
                                        //获取下属设备U位
                                        int UNumStart = intValueConvert(data.get(deviceUIndex)) + 1;
                                        for (int x = 0; x < UHeight; x++) {
                                            UNumStart += x;
                                            V6800SetUIndexColorDataListParam colorDataListParam = new V6800SetUIndexColorDataListParam();
                                            colorDataListParam.setU_index(UNumStart);
                                            colorDataListParam.setColor_code(lightState.getStatus());
                                            u_color_data.add(colorDataListParam);
                                        }
                                    }
                                }
                            }

                        }
                        colorJsonParam.setU_color_data(u_color_data);
                    }
                    indexColorList.add(colorJsonParam);
                }
                colorParam.setData(indexColorList);
                //设置上架指示灯
                sendUManageLightState(gatewaySn, colorParam);
            }

        }

    }


    public List<V6800InitDataInfo> getInitDataInfo(Query query){
        return uNumManageMapper.find(query);
    }

}
